package com.cloud.gateway.filter;

import com.cloud.common.exception.BaseException;
import com.cloud.gateway.contant.GatewayConstant;
import com.cloud.gateway.enums.GatewayCode;
import com.cloud.gateway.properties.WhiteListProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;


/**
 * @author 王霄
 * @date 2022/8/13 17:52
 */
@Component
@Order(0)
@EnableConfigurationProperties(value = WhiteListProperties.class)
@Slf4j
public class AuthenticationFilter implements GlobalFilter {

    @Resource
    private WhiteListProperties whiteListProperties;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String currentUrl = exchange.getRequest().getURI().getPath();

        //1：白名单过滤,比如/oauth/**
        if (isWhiteUrl(currentUrl)) {
            return chain.filter(exchange);
        }

        //2：从请求头中解析token
        String token = exchange.getRequest()
                .getHeaders()
                .getFirst(GatewayConstant.REQUEST_LOGIN_TOKEN_KEY);

        //3：检查token是否为空
        if (StringUtils.isEmpty(token)) {
            log.error("token为空, requestUrl: {}", currentUrl);
            throw new BaseException(GatewayCode.NO_AUTH.getCode(), GatewayCode.NO_AUTH.getMsg());
        }

        //4：校验token有效性
        Object userObj = redisTemplate.opsForValue().get(GatewayConstant.USER_AUTH_TOKEN_REDIS_PREFIX + token);
        if (userObj == null) {
            log.error("token已失效, requestUrl: {}, token: {},", currentUrl, token);
            throw new BaseException(GatewayCode.NO_AUTH.getCode(), GatewayCode.NO_AUTH.getMsg());
        }

        return chain.filter(exchange);
    }

    private boolean isWhiteUrl(String currentUrl) {
        //路径匹配器(简介SpringMvc拦截器的匹配器)
        //比如/oauth/** 可以匹配/oauth/token    /oauth/check_token等
        PathMatcher pathMatcher = new AntPathMatcher();
        for (String skipPath : whiteListProperties.getWhiteList()) {
            if (pathMatcher.match(skipPath, currentUrl)) {
                return true;
            }
        }
        return false;
    }
}
